<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>读书笔记：ES6标准入门—阮一峰 | YTBlog</title>
    <meta name="generator" content="VuePress 1.5.2">
    
    <meta name="description" content="前端技术分享">
    <link rel="preload" href="/ytblog/assets/css/0.styles.cb920d31.css" as="style"><link rel="preload" href="/ytblog/assets/js/app.5ba5dcf6.js" as="script"><link rel="preload" href="/ytblog/assets/js/2.f25dafc3.js" as="script"><link rel="preload" href="/ytblog/assets/js/6.60c7b6d3.js" as="script"><link rel="prefetch" href="/ytblog/assets/js/10.5a02d3b2.js"><link rel="prefetch" href="/ytblog/assets/js/11.44a85492.js"><link rel="prefetch" href="/ytblog/assets/js/12.66c94e70.js"><link rel="prefetch" href="/ytblog/assets/js/13.fbec9428.js"><link rel="prefetch" href="/ytblog/assets/js/3.1ec314c7.js"><link rel="prefetch" href="/ytblog/assets/js/4.6f6a54bd.js"><link rel="prefetch" href="/ytblog/assets/js/5.64df639e.js"><link rel="prefetch" href="/ytblog/assets/js/7.7c06f209.js"><link rel="prefetch" href="/ytblog/assets/js/8.f6875229.js"><link rel="prefetch" href="/ytblog/assets/js/9.6f0d250c.js">
    <link rel="stylesheet" href="/ytblog/assets/css/0.styles.cb920d31.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/ytblog/" class="home-link router-link-active"><!----> <span class="site-name">YTBlog</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/ytblog/" class="nav-link">
  主页
</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="练手小项目" class="dropdown-title"><span class="title">练手小项目</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/ytblog/HTML/" class="nav-link">
  HTML&amp;CSS
</a></li><li class="dropdown-item"><!----> <a href="/ytblog/JavaScript/" class="nav-link">
  JavaScript
</a></li><li class="dropdown-item"><!----> <a href="/ytblog/jquery/" class="nav-link">
  jquery
</a></li><li class="dropdown-item"><!----> <a href="/ytblog/vue/" class="nav-link">
  vue
</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="前端一些概念理解" class="dropdown-title"><span class="title">前端一些概念理解</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/ytblog/CSS/" class="nav-link">
  知识点整理
</a></li><li class="dropdown-item"><!----> <a href="/ytblog/ES6/" aria-current="page" class="nav-link router-link-exact-active router-link-active">
  读书笔记
</a></li></ul></div></div> <!----></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><a href="/ytblog/" class="nav-link">
  主页
</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="练手小项目" class="dropdown-title"><span class="title">练手小项目</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/ytblog/HTML/" class="nav-link">
  HTML&amp;CSS
</a></li><li class="dropdown-item"><!----> <a href="/ytblog/JavaScript/" class="nav-link">
  JavaScript
</a></li><li class="dropdown-item"><!----> <a href="/ytblog/jquery/" class="nav-link">
  jquery
</a></li><li class="dropdown-item"><!----> <a href="/ytblog/vue/" class="nav-link">
  vue
</a></li></ul></div></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="前端一些概念理解" class="dropdown-title"><span class="title">前端一些概念理解</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/ytblog/CSS/" class="nav-link">
  知识点整理
</a></li><li class="dropdown-item"><!----> <a href="/ytblog/ES6/" aria-current="page" class="nav-link router-link-exact-active router-link-active">
  读书笔记
</a></li></ul></div></div> <!----></nav>  <ul class="sidebar-links"><li><section class="sidebar-group depth-0"><p class="sidebar-heading open"><span>读书笔记：ES6标准入门—阮一峰</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/ytblog/ES6/#_1-let和const命令" class="sidebar-link">1. let和const命令</a><ul class="sidebar-sub-headers"></ul></li><li><a href="/ytblog/ES6/#_2-解构" class="sidebar-link">2. 解构</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/ytblog/ES6/#_1）数组的解构：" class="sidebar-link">1）数组的解构：</a></li><li class="sidebar-sub-header"><a href="/ytblog/ES6/#_2）对象的解构：" class="sidebar-link">2）对象的解构：</a></li><li class="sidebar-sub-header"><a href="/ytblog/ES6/#_3-字符串的解构" class="sidebar-link">3) 字符串的解构</a></li><li class="sidebar-sub-header"><a href="/ytblog/ES6/#_4）函数的参数可以使用解构" class="sidebar-link">4）函数的参数可以使用解构</a></li><li class="sidebar-sub-header"><a href="/ytblog/ES6/#其他" class="sidebar-link">其他</a></li><li class="sidebar-sub-header"><a href="/ytblog/ES6/#作用：" class="sidebar-link">作用：</a></li></ul></li><li><a href="/ytblog/ES6/#_3-字符串的扩展" class="sidebar-link">3. 字符串的扩展</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/ytblog/ES6/#模板字符串" class="sidebar-link">模板字符串</a></li></ul></li><li><a href="/ytblog/ES6/#_4-函数的扩展" class="sidebar-link">4. 函数的扩展</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/ytblog/ES6/#箭头函数" class="sidebar-link">箭头函数</a></li></ul></li><li><a href="/ytblog/ES6/#_5-数组的扩展" class="sidebar-link">5. 数组的扩展</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/ytblog/ES6/#扩展运算符" class="sidebar-link">扩展运算符</a></li><li class="sidebar-sub-header"><a href="/ytblog/ES6/#方法" class="sidebar-link">方法</a></li></ul></li><li><a href="/ytblog/ES6/#_6-对象" class="sidebar-link">6. 对象</a><ul class="sidebar-sub-headers"></ul></li><li><a href="/ytblog/ES6/#_7-symbol" class="sidebar-link">7. symbol</a><ul class="sidebar-sub-headers"></ul></li><li><a href="/ytblog/ES6/#_8-set和map" class="sidebar-link">8. set和map</a><ul class="sidebar-sub-headers"></ul></li><li><a href="/ytblog/ES6/#_9-proxy" class="sidebar-link">9. proxy</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/ytblog/ES6/#reflect" class="sidebar-link">reflect</a></li></ul></li><li><a href="/ytblog/ES6/#_10-promise" class="sidebar-link">10. promise</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/ytblog/ES6/#promise-all（）" class="sidebar-link">Promise.all（）</a></li><li class="sidebar-sub-header"><a href="/ytblog/ES6/#promise-race（）" class="sidebar-link">Promise.race（）</a></li></ul></li><li><a href="/ytblog/ES6/#_11-iterator" class="sidebar-link">11. iterator</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/ytblog/ES6/#一些调用iterotor接口的场合：" class="sidebar-link">一些调用iterotor接口的场合：</a></li><li class="sidebar-sub-header"><a href="/ytblog/ES6/#generator：" class="sidebar-link">generator：</a></li></ul></li><li><a href="/ytblog/ES6/#_12-async（async）" class="sidebar-link">12. async（async）</a><ul class="sidebar-sub-headers"></ul></li><li><a href="/ytblog/ES6/#_13-class" class="sidebar-link">13. class</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/ytblog/ES6/#继承：" class="sidebar-link">继承：</a></li></ul></li><li><a href="/ytblog/ES6/#_1-tcp-ip协议族" class="sidebar-link">1. TCP/IP协议族</a><ul class="sidebar-sub-headers"></ul></li><li><a href="/ytblog/ES6/#_2-简单的http协议" class="sidebar-link">2. 简单的HTTP协议</a><ul class="sidebar-sub-headers"></ul></li><li><a href="/ytblog/ES6/#_3-报文" class="sidebar-link">3. 报文</a><ul class="sidebar-sub-headers"></ul></li><li><a href="/ytblog/ES6/#_4-状态码" class="sidebar-link">4. 状态码</a><ul class="sidebar-sub-headers"></ul></li><li><a href="/ytblog/ES6/#_5-https" class="sidebar-link">5. HTTPS</a><ul class="sidebar-sub-headers"></ul></li><li><a href="/ytblog/ES6/#_6-http-2-0" class="sidebar-link">6. HTTP 2.0</a><ul class="sidebar-sub-headers"></ul></li><li><a href="/ytblog/ES6/#_7-一些攻击方法" class="sidebar-link">7. 一些攻击方法</a><ul class="sidebar-sub-headers"></ul></li><li><a href="/ytblog/ES6/#_1-模板编译" class="sidebar-link">1. 模板编译</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/ytblog/ES6/#解析器：" class="sidebar-link">解析器：</a></li><li class="sidebar-sub-header"><a href="/ytblog/ES6/#优化器：" class="sidebar-link">优化器：</a></li><li class="sidebar-sub-header"><a href="/ytblog/ES6/#代码生成器：" class="sidebar-link">代码生成器：</a></li></ul></li><li><a href="/ytblog/ES6/#_2-变化侦测" class="sidebar-link">2. 变化侦测</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/ytblog/ES6/#array的变化侦测" class="sidebar-link">Array的变化侦测:</a></li></ul></li><li><a href="/ytblog/ES6/#_3-虚拟dom" class="sidebar-link">3. 虚拟DOM</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/ytblog/ES6/#patch：" class="sidebar-link">patch：</a></li></ul></li><li><a href="/ytblog/ES6/#_4-生命周期。" class="sidebar-link">4. 生命周期。</a><ul class="sidebar-sub-headers"></ul></li></ul></section></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><h1 id="读书笔记：es6标准入门-阮一峰"><a href="#读书笔记：es6标准入门-阮一峰" class="header-anchor">#</a> 读书笔记：ES6标准入门—阮一峰</h1> <p>前端是一项发展极快的行业，并且由于没有专业的科班培养导致前端并没有一个公认的培养体系，学习前端的过程大多是自发的在网上学习的过程。</p> <p>我在学习前端的过程中，学习路线主要是：w3cshool菜鸟教程—B站找详细视频并练习小项目—看面试题这种方式进行，但是看面试题的过程中发现原来很多细节在学习过程中是被漏掉的，在检索面试题答案的过程中发现仅看答案的内容是不够完全不够严谨的，一旦往深处追究又是一片空白。并且，哪怕是更全面的详解等内容，网上复制粘贴的现象非常严重，我甚至在知乎上看到同一片文章的三次推送，作者完全不同，更重要的是原本很简单的问题讲的又长又臭——最过分的是结论还是错的，与在权威书的内容相悖。</p> <p>因此个人认为，想牢固掌握前端的基础内容，读书是必不可少的一部分。看源码看标准难度太大，网络上的文章有时候又不够权威和严谨，而书是很好的对源码和标准的解读和提炼。我很喜欢看书的序，作者都是很真情实感的在抒发自己对这本书的感情，因此书本是深入理解一项技术的很好的路径。</p> <p>因为这部分的笔记主要还是给自己看，面试前过一遍给记忆提示，因此写的不够详细。本身书就是二手的东西，不够全面，我自己再看的时候有些东西还得参考另一本深入理解ES6去补全知识点，因此建议看书。</p> <h2 id="_1-let和const命令"><a href="#_1-let和const命令" class="header-anchor">#</a> 1. let和const命令</h2> <p>基础的for(var i=0;a&lt;nums.length;i++)循环中，用var声明的变量为全局变量，let仅在本轮循环中有效。</p> <p>临时性死区（TDZ）：若有let声明在代码块内，则在声明以前使用就会报错，哪怕typeof（根本没声明都不会报错：undefined）也不安全。</p> <p>let和const不允许重复声明，会报错。</p> <p>ES5声明方式只有全局+函数：</p> <p>可能会导致内层变量会覆盖外层变量，比如函数内部有个判断，如果执行则声明一个变量，这个变量只希望在内部使用，但哪怕不执行这个语句，函数内部使用同名变量的也会因为变量提升而被覆盖。</p> <p>第二种场景，用来技术的循环变量泄露为全局变量，比如for循环中的i</p> <p>块级作用域的出现，实际上使得获得广泛应用的立即执行匿名函数不再必要了。</p> <p>const：块级作用域、不能改，声明时必须赋值，之前被let和var声明了也报错（反过来也一样）。</p> <p>简单数据类型：变量指向内存地址，值就保存在内存地址中；</p> <p>复杂数据类型：变量指向内存地址，内存地址保存指针，而不是保存复杂类型的值。</p> <p>const：变量指向的内存地址不能变。因此，若用const声明对象，对象内部的东西还是可以改变的，若实在要用对象，可以用 const foo = object.freeze({})的方法声明。</p> <p>ES5：var function两种声明方式</p> <p>ES6：let const import class</p> <p>var声明的变量是顶层变量，即在window中可以找到，因此无法在编译时提示未声明，而ES6新增的声明方式，不再是顶层变量，而是全局变量，无法在window中找到。</p> <h2 id="_2-解构"><a href="#_2-解构" class="header-anchor">#</a> 2. 解构</h2> <h3 id="_1）数组的解构："><a href="#_1）数组的解构：" class="header-anchor">#</a> 1）数组的解构：</h3> <p>let [a,[b,c]]=[a,[2,3]] 嵌套结构</p> <p>let[a,,b]=[1,2,3]结构缺值</p> <p>let [x,y,...z]=['a'] x = a,y=undefined,z=[]</p> <p>等号右边必须是又iterator接口的表达式，数组，map等都是可以的</p> <p>结构可以有默认值，在完全等于undefined的时候生效</p> <p>let[x=1,y=x]=[]是允许的，但let[x=y,y=1]=[]是不被允许的</p> <p>let[x=1,y=x]=[2]中，y=2</p> <h3 id="_2）对象的解构："><a href="#_2）对象的解构：" class="header-anchor">#</a> 2）对象的解构：</h3> <p>变量必须与属性（key）同名</p> <p>let {key:value} = {key:value} 在key名相等的情况下，value会赋值给value。若被赋值的对象没有value，则默认key：key</p> <p>对象的解构同样可以设置默认值，在完全等于undefined的情况下生效。</p> <p>如果是已经声明的变量，则要加括号（{x} = {x:1}）,x已声明</p> <p>数组的本质也是对象，也可以用对象的解构 let{0:first,[arr.length-1]:last} = arr，会将数组第一个数赋给first</p> <h3 id="_3-字符串的解构"><a href="#_3-字符串的解构" class="header-anchor">#</a> 3) 字符串的解构</h3> <p>[a,b]=&quot;he&quot; a=&quot;h&quot;</p> <p>如果右边为数值或者布尔值，则会转化为对象</p> <div class="language- extra-class"><pre><code>		let {toString:s} = 123;
		s === Number.prototype.toString
</code></pre></div><h3 id="_4）函数的参数可以使用解构"><a href="#_4）函数的参数可以使用解构" class="header-anchor">#</a> 4）函数的参数可以使用解构</h3> <p>声明 fn（[a,b]），使用fn（[1,2]）</p> <h3 id="其他"><a href="#其他" class="header-anchor">#</a> 其他</h3> <p>不能用圆括号，只有是被赋值的变量才能用圆括号。</p> <h3 id="作用："><a href="#作用：" class="header-anchor">#</a> 作用：</h3> <ul><li>变量的交换</li> <li>从函数返回多个值 let [a,b,c] = fn()</li> <li>函数参数的定义，有序用数组，无序用对象</li> <li>提取json数据一次性赋值多个变量</li> <li>函数参数的默认值</li> <li>遍历map解构 for（let [k,v] of map）</li> <li>输入模块的指定方法</li></ul> <h2 id="_3-字符串的扩展"><a href="#_3-字符串的扩展" class="header-anchor">#</a> 3. 字符串的扩展</h2> <p>可以用for of循环，遍历出来的是value</p> <p>新增at方法，可以at中文了，原来charAt只能at英文，出来正确的结果，中文出来是两个编码中的一个</p> <h4 id="新增方法"><a href="#新增方法" class="header-anchor">#</a> 新增方法</h4> <p>include（）：返回布尔值，表示是否找到了参数字符串</p> <p>startWith（）：返回布尔值，表示参数字符串是否头部</p> <p>endsWith（）：返回布尔值，表示参数字符串是否在尾部</p> <p>repeat（num）：返回一个新字符串，重复num次，小数会被向下取整，负数或者无穷会被报错，如果0到-1则取0</p> <p>x.padStart（n,str）:在x字符串之前补上n个str（若str有5个字母，n是3，则是用前三个字母，超过五个也顺延）</p> <p>x.padEnd (n,str)：在x字符串之后补上n个str中的字母。</p> <h3 id="模板字符串"><a href="#模板字符串" class="header-anchor">#</a> 模板字符串</h3> <p><code>多行输入，可以用${}加入变量</code></p> <h2 id="_4-函数的扩展"><a href="#_4-函数的扩展" class="header-anchor">#</a> 4. 函数的扩展</h2> <p>ES6之前用：y = y||&quot;wirld&quot;,缺点是如果y被赋值false会被认为没赋值</p> <p>ES6可以直接用等号设定默认值</p> <p>可以配合解构使用：</p> <p>双重解构的两种写法</p> <div class="language- extra-class"><pre><code>		function m1({x=0;y=0}={}){return x+y}
		function m2({x,y}={x:0,y:0}){return x+y}
</code></pre></div><p>两种写法在都有赋值或都没赋值的时候结果是一样的，在仅有一个有值的时候，函数的默认值会失效，而解构的默认值还存在，因此第一种写法可以使另一个变量的值为默认值</p> <p>默认值要在尾参数，不然不生效。不能f(,2),除非用f（undefined，2）</p> <p>函数的length属性值没有置顶默认值的参数的个数，这个个数只算第一个设置默认值参数的前面</p> <p>一旦设置了默认值，参数会形成单独的作用域,TDZ生效，使用外部却又不改变外部 f（y = x）{let x = 1}这里x会用window里的，而不是1，且内部用不会改变外部。</p> <p>如果默认值在声明时还不存在，则会报错。</p> <p>应用：省略必要参数时报错 f(a = 抛错函数执行)</p> <p>rest参数：...变量名，变量名的变量时一个数组，只能放在最后一个</p> <p>严格模式：只要用了默认值，那就不能在内部“use strict”了</p> <p>name属性，主要差别在匿名部分 var f = function(){},es5的f.name属性会输出空，es6会输出“f”。</p> <p>对于不是匿名函数  var f = function baz(){},则都会输出baz</p> <h3 id="箭头函数"><a href="#箭头函数" class="header-anchor">#</a> 箭头函数</h3> <p>最简单： var f = v=&gt;v 输入参数是v，返回v</p> <p>多参数：(a,b)=&gt;a+b 输入ab，返回a+b</p> <p>多语句：语句要用{}括起来，且要自己写return语句</p> <h4 id="注意事项："><a href="#注意事项：" class="header-anchor">#</a> 注意事项：</h4> <ul><li>this是定义时的对象，而不是使用时的对象</li> <li>不可以当构造函数，即不能用new</li> <li>不可以用arguments对象，可以用rest参数...args</li> <li>不可以用yield命令，因此不能用作generator函数</li></ul> <p>this实际上用了var that = this，内部都用that  foo.call({}),这是定义，里面this都指这个空对象。如果foo内部用window方法调用，调用的回调函数使用箭头函数，那么箭头函数的this会指向这个空对象。</p> <p>函数绑定对象   对象：：函数 相当于函数。bind（对象）</p> <h4 id="尾调用优化：不会再保存内部变量"><a href="#尾调用优化：不会再保存内部变量" class="header-anchor">#</a> 尾调用优化：不会再保存内部变量</h4> <p>return的不能是内部函数，也不能return一个函数再来个计算</p> <h4 id="尾递归"><a href="#尾递归" class="header-anchor">#</a> 尾递归</h4> <p>比如斐波那契数列：</p> <p>传统写法：</p> <div class="language- extra-class"><pre><code>		function f(n){
			if (n&lt;=1) return 1
			return f(n-1)+f(n-2)
		}
</code></pre></div><p>尾递归优化写法：</p> <div class="language- extra-class"><pre><code>		function f2(n,arc1=1,arc2=1){
			if (n&lt;=1) return acr2
			return f2(n-1,arc2,arc1+arc2)
		}
</code></pre></div><h2 id="_5-数组的扩展"><a href="#_5-数组的扩展" class="header-anchor">#</a> 5. 数组的扩展</h2> <h3 id="扩展运算符"><a href="#扩展运算符" class="header-anchor">#</a> 扩展运算符</h3> <p>...可以将一个数组转化为用逗号分隔的参数序列，空数组不产生任何效果[...[],1]=[1]</p> <p>作用：替代apply，apply的参数输入方式为数组，call为序列，bind为直接绑定，不会直接运行。</p> <p>xw.say.call(xh);  xw.say.apply(xh);  xw.say.bind(xh)(); bind传参可以和call一样，也可以再后面哪个括号中输入参数</p> <p>原先的max，可以用apply输入数组：</p> <p>Math.max.apply(null,arr)</p> <p>push方法 arr2.push(...arr)</p> <p>合并数组：原 a.concat(more)，现[...a,...more]</p> <p>解构赋值：原 a = list[0] rest = list.slice(1)，现[a,...rest]  如果时空的 a为undefined rest为[]</p> <p>扩展运算符解构赋值只能放后面</p> <p>可以把字符串等又iterator接口的转化为真正的数组</p> <h3 id="方法"><a href="#方法" class="header-anchor">#</a> 方法</h3> <p>Array.from方法可以把类似数组的对象（有length）和有iterator接口的对象转化为真正的数组</p> <p>新增of方法，括号里的序列为数组参数。为了改变Array()方法输入1个参数时表示规模，多个参数时表示数组参数的问题</p> <p>Array.of(3) = [3]    Array(3)=[,,,]  Array(3,4) = [3,4]</p> <p>arr.fill(7) = [7,7,7]</p> <h5 id="遍历："><a href="#遍历：" class="header-anchor">#</a> 遍历：</h5> <p>for of循环：keys（） values（） entries（）返回Array Iterator对象，其中entries可用[index,value]解构</p> <p>includes（value，start（含）），返回true和false</p> <h2 id="_6-对象"><a href="#_6-对象" class="header-anchor">#</a> 6. 对象</h2> <h4 id="简写："><a href="#简写：" class="header-anchor">#</a> 简写：</h4> <p>baz = {foo}  foo是一个变量名，key为foo，value为foo的变量值</p> <p>不写值 function f（x，y）{return {x，y}} f（1，2）会返回一个对象，属性时x，y，值是1，2</p> <h4 id="属性名："><a href="#属性名：" class="header-anchor">#</a> 属性名：</h4> <p>obj.foo = 1  foo是个字符串（标识符），也可以用中括号里面可以是表达式或者变量名，obj[&quot;a&quot;+&quot;b&quot;] = obj.ab</p> <h4 id="其他："><a href="#其他：" class="header-anchor">#</a> 其他：</h4> <p>do.bind().name = &quot;bound do&quot;</p> <p>enumerable可枚举  在for in循环，obj.keys，json.stringfy Object.assign：将源对象的所有属性复制到目标对象中（target，so1，so2） 中如果设置为false会被忽略</p> <h4 id="属性的遍历"><a href="#属性的遍历" class="header-anchor">#</a> 属性的遍历</h4> <ul><li>for in：可枚举，不含symbol</li> <li>Object.keys（obj）：返回数组，可枚举，不含symbol</li> <li>Object.getOwnPropertyNames(obj)：返回数组，含不可枚举，不含symbol</li> <li>Object.getOwnPropertySymbols(obj)：返回数组，只有symbol</li> <li>Reflect.ownKeys(obj)：返回数组，所有属性    顺序：数字升序、字符串时间、symbol时间</li></ul> <p>扩展运算符可以在对象中使用，是浅复制，不继承原型的对象属性</p> <h2 id="_7-symbol"><a href="#_7-symbol" class="header-anchor">#</a> 7. symbol</h2> <p>因为对象和属性名都是字符串，这很容易造成属性名冲突。</p> <p>七种数据类型：undefined null Boolean string number symbol object</p> <p>定义方法 let symbol = Symbol(&quot;str&quot;)</p> <p>不能用new，会报错，若标识符是个对象则调用tostring方法。</p> <p>不能运算，也不能用${}调用</p> <p>可以用string或者symbol.toSring方法，转为’symbol（str）‘</p> <p>Boolean（symbol）为true</p> <p>作为属性，不能用点，只能用[]</p> <p>可以用于定义一组常量，保证常量不相等。</p> <p>DEBUG:Symbol（“debug”）</p> <p>比如可以消除魔术字符串  switch（shape） case（shapetype.triangle）这样可以保证每个shape不一样。shaptype.t = symbol（“t”）</p> <p>let s1 = Symbol.for(&quot;for&quot;)：可以把多个变量名注册成同一个symbol</p> <p>Symbol.keyFor(s1) ：可以返回&quot;for&quot;</p> <p>遍历：Object.getOwnPropertySymbols(obj)</p> <h2 id="_8-set和map"><a href="#_8-set和map" class="header-anchor">#</a> 8. set和map</h2> <h4 id="let-set-new-set-arr"><a href="#let-set-new-set-arr" class="header-anchor">#</a> let set = new Set(arr)</h4> <p>去重的方法 let arr = [...new Set(arr)] 内部用===，但NaN这里等于NaN</p> <p>属性：constructor size</p> <p>方法：add(value)  返回set  delete(value) 返回true has（value ）返回true   clear()返回null</p> <p>遍历：for of循环  keys() values() entries()  返回Set Iterator</p> <p>forEach（（item，index）=&gt;）可以直接用，map filter等需要转换成数组用。</p> <p>set的在数据集上的操作方法</p> <p>交集： let res = new Set([...a,...b])</p> <p>并集：let res = new Set([...a].filter(x)=&gt;b.has(x))</p> <p>差集：let res = new Set([...a].filter(x)=&gt;!b.has(x))</p> <p>set的取值一般只能转化成数组，因为key=value</p> <h4 id="weakset"><a href="#weakset" class="header-anchor">#</a> WeakSet</h4> <ul><li>成员只能是对象（数组是对象）</li> <li>弱应用，即垃圾回收可以不考虑</li></ul> <p>方法：add delete has</p> <p>属性：没有size了，也不能遍历</p> <p>作用：存DOM节点</p> <h4 id="map"><a href="#map" class="header-anchor">#</a> Map</h4> <p>可以把对象作为键名，属性有size</p> <p>let map = new Map([ [k,v],[k,v],[k,v] ])</p> <p>方法：set(key,value) get(key)    has(key)   delete(key) clear()</p> <p>遍历，和set一样 entries [key,value]</p> <p>扩展运算符[  [],[],[]   ]</p> <h4 id="weakmap"><a href="#weakmap" class="header-anchor">#</a> WeakMap</h4> <ul><li>键名只能是对象（null除外）</li> <li>弱应用，即垃圾回收可以不考虑</li></ul> <p>作用：为DOM元素存储数据，比如点击次数。当dom节点没了，就没了，不会造成内存泄漏</p> <p>或者存储时间的回调函数和属性等等</p> <p>属性：无size  方法：无clear</p> <h2 id="_9-proxy"><a href="#_9-proxy" class="header-anchor">#</a> 9. proxy</h2> <p>var p = new Proxy({被代理的对象},{get,set等等})</p> <p>get : function(target,key,receiver)  target:被代理的对象  key：属性  receiver：p</p> <p>set : function(target,key,value,receiver)</p> <p>apply : function(target,ctx,args)  拦截函数调用（被代理对象是个函数）ctx：上下文对象（apply等）</p> <p>has(target,key)  拦截hasproperty操作  &quot;a&quot; in p</p> <p>construct(target,args,newtarget) 拦截new操作</p> <p>deleteProperty(target,key) 返回布尔  拦截delete p.a</p> <p>defineproperty(target,key,descriptor) 拦截Object.defineProperty</p> <p>ownkeys(target) 拦截keys()</p> <h3 id="reflect"><a href="#reflect" class="header-anchor">#</a> reflect</h3> <ul><li>语言内部的方法放到了reflect上，比如object.defineproperty</li> <li>修改了一些返回结果，使其合理，如上一个比如会返回false而不是报错</li> <li>让object操作都变为了函数，比如 “a” in obj 变成了 reflect.has(obj,&quot;a&quot;)</li> <li>与proxy方法一一对应，可以调用对用方法使其完成默认操作。</li></ul> <h2 id="_10-promise"><a href="#_10-promise" class="header-anchor">#</a> 10. promise</h2> <p>promise的状态不受外界影响</p> <p>三个状态：<strong>pending</strong>（进行中），<strong>fulfilled</strong>（成功），<strong>rejected</strong>（失败）。一旦由进行中变为成功/失败，状态就不会再改变</p> <p>一旦状态改变就不会再变，任何时候都可以得到这个结果。</p> <p>缺点是<strong>无法取消</strong>，一旦新建它就会<strong>立即执行</strong>。如果捕蛇者回调函数，内部的错误就不会反应到外部。pending状态时无法得知目前进展到哪一步。</p> <p>基本用法</p> <div class="language- extra-class"><pre><code>		var promise = new Promise(function(resolve,reject){
			//some &lt;code&gt;&lt;/code&gt;
			if(){
				resolve(value)
			}else{
				reject(error)
			}
		})
</code></pre></div><p>其中，some code会立即执行，如果调用了resolve/reject，则表明由pending到了fulfilled/rejected</p> <p>then方法接受两个回调函数</p> <div class="language- extra-class"><pre><code>		promise.then(function(value){
			//成功了执行这里，value就是promise对象传过来的value
		},function(error){
			//失败了执行这里
		}
		)
</code></pre></div><p>执行完reselve如果后面还有代码还是会继续执行的，但不改变状态。</p> <p>than函数在所有同步任务执行完成之后执行。即resolve后面的语句先执行，然后是整个代码后面的执行，所有任务完成之后再than</p> <p>than：返回promise对象，因此可以用链式写法，上一个than return的内容会作为下一个than的value，即传入的参数。</p> <p>catch：无论前面有几个than或者开头的promise，他都能捕捉到所有错误。因此一般than只写fulfilled的回调函数，reject函数放到catch里。</p> <p>promise对象的错误具有冒泡性质，会一直向后传递，直到被捕获为止。</p> <h3 id="promise-all（）"><a href="#promise-all（）" class="header-anchor">#</a> Promise.all（）</h3> <p>var PA = Promise.all（[p1,p2,p3]）</p> <p>只有1，2，3都成功了才会执行</p> <p>PA.than(function(value){},function(error){})，其中value为所有子对象的返回值组成的数组，error为第一个失败的子对象返回值</p> <p>注意：如果子对象自身定义了catch方法，则不会冒泡到PA上，因此还是成功状态。也就是说实际的对象是catch之后返回的promise对象，那么一般来说状态还是成功的状态。</p> <h3 id="promise-race（）"><a href="#promise-race（）" class="header-anchor">#</a> Promise.race（）</h3> <p>率先改变状态的返回值会给PR用，可以用来设置ajax请求的时限，一个请求，一个延时，延时函数内部是个reject，在pr用catch捕捉。</p> <h4 id="其他：-2"><a href="#其他：-2" class="header-anchor">#</a> 其他：</h4> <p>Promise.resolve():可以把现有对象转化为promise对象</p> <p>done方法：一般放在尾部，和than方法一样用，可以保证捕捉到任何错误</p> <p>finally方法：只有一个回调函数，无论如何都会执行。</p> <h2 id="_11-iterator"><a href="#_11-iterator" class="header-anchor">#</a> 11. iterator</h2> <p>js原生的集合数据解构主要是array，object，map，set</p> <h4 id="iterator遍历器作用："><a href="#iterator遍历器作用：" class="header-anchor">#</a> iterator遍历器作用：</h4> <ul><li>为各种数据解构提供一个统一的、简便的访问接口；</li> <li>使得数据结构的成员能够按某种次序排列</li> <li>ES6新增for of循环，遍历器主要供for of消费</li></ul> <p>过程：</p> <ol><li>创建一个指针对象，指向当前数据解构的起始位置。也就是说，遍历器本质上就是一个指针对象。</li> <li>调用next方法，可以将指针指向数据结构的下一个成员。</li> <li>不断调用next方法，直到它指向数据结构的结束位置。</li></ol> <p>每次调用next方法都会返回数据结构的当前</p> <h4 id="symbol-iterator属性："><a href="#symbol-iterator属性：" class="header-anchor">#</a> symbol.iterator属性：</h4> <p>调用该方法可以生成一个遍历器</p> <div class="language- extra-class"><pre class="language-text"><code>			let arr = [1,2,3];
			let i = arr[Symbol.iterator]()
			console.log(i)
			console.log(i.next())
			console.log(arr.values())
</code></pre></div><p>输出结果</p> <p>Array Iterator {}
{value: 1, done: false}
Array Iterator {}</p> <p>最后一个value是undefined ，done是true</p> <h5 id="原生有这个接口的有：array-map-set-string-typedarray-函数的arguments对象，nodelist对象。只有有这个接口才能用for-of循环。没有的话要在symbol-iterator上部署，这是一个函数。"><a href="#原生有这个接口的有：array-map-set-string-typedarray-函数的arguments对象，nodelist对象。只有有这个接口才能用for-of循环。没有的话要在symbol-iterator上部署，这是一个函数。" class="header-anchor">#</a> 原生有这个接口的有：array map set string typedarray 函数的arguments对象，nodelist对象。只有有这个接口才能用for of循环。没有的话要在Symbol.iterator上部署，这是一个函数。</h5> <h3 id="一些调用iterotor接口的场合："><a href="#一些调用iterotor接口的场合：" class="header-anchor">#</a> 一些调用iterotor接口的场合：</h3> <ul><li>解构赋值</li> <li>扩展运算符</li> <li>yield</li> <li>其他场合：for of；array。from；map（），set（），weak。。。创建的时候；promise。all（），race（）。</li></ul> <p>数组：for in是键名，for of是键值</p> <p>对象：for in可以用，for of不行</p> <h4 id="遍历语法比较："><a href="#遍历语法比较：" class="header-anchor">#</a> 遍历语法比较：</h4> <p>for循环：写法复杂</p> <p>forEach：无法中途跳出</p> <p>for in：只能是键名，适合对象</p> <p>for of：适合数组，语法简洁，可以跳出</p> <h3 id="generator："><a href="#generator：" class="header-anchor">#</a> generator：</h3> <p>基本形式</p> <div class="language- extra-class"><pre class="language-text"><code>			function* hello(){
				yield 1;
				yield 2;
				return 3;
			}
			var hw = hello()
			console.log(hw.next())//{value: 1, done: false}
			console.log(hw.next())// {value: 2, done: false}
			console.log(hw.next())// {value: 3, done: true}
			console.log(hw.next())// {value: undefined, done: true}
</code></pre></div><p>规则：</p> <ul><li>遇到yield就停，输出后面的东西</li> <li>next（）后继续往下执行，直到下一个yield</li> <li>一直到结束或者return，return可以作为返回对象的value属性</li></ul> <p>generator是惰性的，不next不执行。</p> <p>next（value） value会作为上一个yield的返回值</p> <p>比如</p> <div class="language- extra-class"><pre class="language-text"><code>			function* f(){
				for(let i = 0;true;i++){
					var reset = yield i;
					console.log(reset)   //undefined yield本身没有返回值
					if(reset) {i = -1}
				}
			}
			var g = f()
			console.log(g.next())//{value: 0, done: false}
			console.log(g.next())//{value: 1, done: false}
			console.log(g.next(true))//{value: 0, done: false}
</code></pre></div><p>也就是说调用最后一个next之前reset会被作为上一个yield的返回值，即reset被赋值为true，则if生效，i重置为-1，经过i++到下一个yield。输出0.</p> <p>for of循环可以遍历，不会遍历done的内容，即return的不会，return后面的也不会</p> <p>yield* foo（）：调用generator函数</p> <p>比如一个中序遍历</p> <div class="language- extra-class"><pre class="language-text"><code>			function* inorder(t){
				if(t){
					yield* inorder(t.left);
					yield t.value;
					yield* inorder(t.right)
				}
			}
</code></pre></div><p>可以用for of循环把结果push到result数组里</p> <h2 id="_12-async（async）"><a href="#_12-async（async）" class="header-anchor">#</a> 12. async（async）</h2> <p>async是generator函数的语法糖，把*换成了async（function  *变成了async function），把yield换成了await</p> <h4 id="改进："><a href="#改进：" class="header-anchor">#</a> 改进：</h4> <ul><li>内置执行器：generator函数执行必须依靠co模块（或者next不断调用到结束），而async自带了执行器，也就是说async函数可以和普通函数一样用（）执行</li> <li>更好的语义：比起星号和yield，语义更清楚了。</li> <li>更广的适用性：co模块约定，yield后面只能是thunk函数或promise对象，而await后面可以是promise对象和原始数据类型</li> <li>返回值是promise：这比generator返回值是iterator对象方便了许多。可以用than指定下一步操作</li></ul> <p>进一步说，async函数完全可以看作由多个异步操作包装成的一个promise对象，而await命令就是内部then命令的语法糖</p> <p>正常情况下await后面是一个promise对象，如果不是，会被转成一个立即resolve的promise对象，比如数字，数字立即被then接受为value。</p> <p>await Promise.reject('出错了')，可以被catch捕捉到</p> <p>只要await后面的promise变为reject，那么整个函数都会被中断执行</p> <p>我们可以把出错的await放到try catch里，这样后面的await还能执行。</p> <p>或许相似await后面的promise对象后添加一个catch方法，实际错误就只会冒泡到catch上，并返回一个状态成功的promise对象，一样可以继续执行后面的函数。</p> <h2 id="_13-class"><a href="#_13-class" class="header-anchor">#</a> 13. class</h2> <p>传统构造函数定义并生成一个对象：</p> <div class="language-js extra-class"><pre class="language-js"><code>		<span class="token keyword">function</span> <span class="token function">point</span><span class="token punctuation">(</span><span class="token parameter">x<span class="token punctuation">,</span>y</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
			<span class="token keyword">this</span><span class="token punctuation">.</span>x <span class="token operator">=</span> x<span class="token punctuation">;</span>
			<span class="token keyword">this</span><span class="token punctuation">.</span>y <span class="token operator">=</span> y<span class="token punctuation">;</span>
		<span class="token punctuation">}</span>
		point<span class="token punctuation">.</span>prototype<span class="token punctuation">.</span><span class="token function-variable function">toString</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
			<span class="token keyword">return</span> <span class="token string">'('</span><span class="token operator">+</span><span class="token keyword">this</span><span class="token punctuation">.</span>x<span class="token operator">+</span><span class="token string">','</span><span class="token operator">+</span><span class="token keyword">this</span><span class="token punctuation">.</span>y<span class="token operator">+</span><span class="token string">')'</span>
		<span class="token punctuation">}</span>
		<span class="token keyword">var</span> p <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">point</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">)</span>
</code></pre></div><p>class方法</p> <div class="language-js extra-class"><pre class="language-js"><code>		<span class="token keyword">class</span> <span class="token class-name">point</span><span class="token punctuation">{</span>
			<span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">x<span class="token punctuation">,</span>y</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
			    <span class="token keyword">this</span><span class="token punctuation">.</span>x <span class="token operator">=</span> x<span class="token punctuation">;</span>
			    <span class="token keyword">this</span><span class="token punctuation">.</span>y <span class="token operator">=</span> y<span class="token punctuation">;</span>
			<span class="token punctuation">}</span>
			<span class="token comment">//注意这里没有逗号</span>
			<span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
				<span class="token keyword">return</span> <span class="token string">'('</span><span class="token operator">+</span><span class="token keyword">this</span><span class="token punctuation">.</span>x<span class="token operator">+</span><span class="token string">','</span><span class="token operator">+</span><span class="token keyword">this</span><span class="token punctuation">.</span>y<span class="token operator">+</span><span class="token string">')'</span>
			<span class="token punctuation">}</span>
		<span class="token punctuation">}</span>
		<span class="token keyword">var</span> p <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">point</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">)</span>
</code></pre></div><p>注意</p> <div class="language- extra-class"><pre class="language-text"><code>			console.log(typeof point) //function
			console.log(point === point.prototype.constructor) //ture
</code></pre></div><p>也就是说类的数据类型就是函数，类本身就指向构造函数。</p> <p>在类的实例上调用方法，其实就是调用原型上的方法</p> <p>point.ptototype = {constructor（）{}，toString（）{}，toValue（）{}}</p> <p>类的内部定义的所有方法都是不可枚举的（es5定义 Object.keys(point.prototype)//[toString]）</p> <p>类的属性名可以用表达式[表达式]，例如表达式是个变量名，就会被变量的值放进去</p> <p>实例的属性除非显示定义在其本实（即this）上，否则都是定义在原型上</p> <p>const myclass = class me{me.name}会是myclass，而不是me，me只在class内部代码可用，指代当前类</p> <p>当new了之后的调用this.name会出现me</p> <h4 id="私有方法：命名法-前面加-，移除法（公有方法在内部用call调用外部方法），私有方法名字命名为symbol"><a href="#私有方法：命名法-前面加-，移除法（公有方法在内部用call调用外部方法），私有方法名字命名为symbol" class="header-anchor">#</a> 私有方法：命名法(前面加_)，移除法（公有方法在内部用call调用外部方法），私有方法名字命名为symbol</h4> <h4 id="私有属性：还没定下来，目前提案时用-，只能class内部用，外面不能用"><a href="#私有属性：还没定下来，目前提案时用-，只能class内部用，外面不能用" class="header-anchor">#</a> 私有属性：还没定下来，目前提案时用#，只能class内部用，外面不能用</h4> <p>类的方法this指向，默认为类的实例。调用的时候要小心，如果单独把方法拿出来用（对象解构），会找不到this指向的东西。</p> <p>解决办法：构造的时候用bind绑定，或者用箭头函数（箭头函数内部的this会默认指向定义时候的this），或者用代理在获取方法的时候自动绑定</p> <h4 id="get和set：可用对某个属性设置或者读取进行拦截："><a href="#get和set：可用对某个属性设置或者读取进行拦截：" class="header-anchor">#</a> get和set：可用对某个属性设置或者读取进行拦截：</h4> <p>set 属性名（value）{}</p> <p>get 属性名（）{}</p> <h4 id="静态方法：不会被继承"><a href="#静态方法：不会被继承" class="header-anchor">#</a> 静态方法：不会被继承</h4> <p>static classMethod（）{}   类名。calssmethod可用调用  new之后新名。cassmethod不能调用，没有</p> <h4 id="父类的静态方法可用被子类继承"><a href="#父类的静态方法可用被子类继承" class="header-anchor">#</a> 父类的静态方法可用被子类继承</h4> <p>cass son extends foo{}    son.静态方法（）可用</p> <h4 id="只有静态方法没有静态属性"><a href="#只有静态方法没有静态属性" class="header-anchor">#</a> 只有静态方法没有静态属性</h4> <p>prop：2 和static prop：2都无效。可在外边写 类名.属性</p> <h4 id="class的实例属性可用用等式写入类的定义中（不用this），可用不用再constructor方法里定义"><a href="#class的实例属性可用用等式写入类的定义中（不用this），可用不用再constructor方法里定义" class="header-anchor">#</a> class的实例属性可用用等式写入类的定义中（不用this），可用不用再constructor方法里定义</h4> <h4 id="新写法：class的静态属性：static-prop-42；可用等号写"><a href="#新写法：class的静态属性：static-prop-42；可用等号写" class="header-anchor">#</a> 新写法：class的静态属性：static prop = 42；可用等号写</h4> <h3 id="继承："><a href="#继承：" class="header-anchor">#</a> 继承：</h3> <p>class Point{}</p> <p>class son extends Point{</p> <p>constructor(x,y,color){</p> <p>​		super(x,y);//必须先调用父类才能用this指针</p> <p>//原理 A.prototype.constructor.call(B)</p> <p>​		this.color = color;</p> <p>​		}</p> <p>}</p> <p>调用父类的方法名super.方法名（）</p> <p>查父类方法：Object.getPrototypeOf（son）===Point  //true</p> <h4 id="super：作为函数时是构造函数，只能用在构造函数中；作为对象时，在普通方法中指向父类的原型对象，在静态方法中指向父类。"><a href="#super：作为函数时是构造函数，只能用在构造函数中；作为对象时，在普通方法中指向父类的原型对象，在静态方法中指向父类。" class="header-anchor">#</a> super：作为函数时是构造函数，只能用在构造函数中；作为对象时，在普通方法中指向父类的原型对象，在静态方法中指向父类。</h4> <p>super.p（）相当于（A父类，B子类）  A.prototype.p()</p> <p>用super调用父类的方法时，会绑定子类的super</p> <p>super.x赋值等同于this.x。但读super.x等同于父类原型链上的x上，所以一般是undefined</p> <h1 id="读书笔记：图解http-上野-宣"><a href="#读书笔记：图解http-上野-宣" class="header-anchor">#</a> 读书笔记：图解HTTP—上野 宣</h1> <p>这份笔记主要是总结http协议的内容，图解HTTP此书简单易懂。计算机网络是大学计算机的必修课，但是内容还是有些太多以及繁杂，并且和前端相关的部分并没有太过于深入。图解HTTP很好的把前端最重要的http协议以及tcp协议讲的比较清楚。但遗憾的是此书稍微有些老了，HTTP 2.0的部分在写书的时候并没有成为标准，还是有些遗憾。笔者结合图解HTTP以及前端程序员面试笔试宝典，总结了一份以提要为主的笔记。</p> <h2 id="_1-tcp-ip协议族"><a href="#_1-tcp-ip协议族" class="header-anchor">#</a> 1. TCP/IP协议族</h2> <p>TCP/IP是在IP协议的通信过程中，使用到的协议族的统称。</p> <h4 id="主要分为四层："><a href="#主要分为四层：" class="header-anchor">#</a> 主要分为四层：</h4> <p>应用层：FTP、DNS、HTTP、SSL等协议；应用层决定了向用户提供服务时通信的活动。</p> <p>传输层：TCP、UDP等协议；提供处于网络连接中的两台计算机之间的数据传输。</p> <p>网络层：IP；在众多的选项内选择一条传输路线。</p> <p>链路层（数据链路层、网络接口层）：用来处理连接网络的硬件部分。操作系统、硬件驱动、网卡、光纤</p> <p>总的来说：发起HTTP请求—传输层用TCP协议分割—网络层找到对方IP，增加MAC地址</p> <p>OSI的七层网络协议：</p> <p>应用层、表示层、会话层（应用层），传输层（传输层），网络层（网络层），数据链路层（网卡层），物理层（（硬件））</p> <p>123：应用程序    45：操作系统     67：设备驱动程序与网络接口</p> <h4 id="各种协议与http协议的关系："><a href="#各种协议与http协议的关系：" class="header-anchor">#</a> 各种协议与HTTP协议的关系：</h4> <ol><li>客户端向DNS请求IP地址</li> <li>生成HTTP请求报文</li> <li>TCP将保温分割成报文段，把每个报文可靠地传给对方</li> <li>路由器IP寻址，一遍中转一遍传送</li> <li>TCP重组报文</li> <li>HTTP对web服务器请求的内容进行处理</li></ol> <h2 id="_2-简单的http协议"><a href="#_2-简单的http协议" class="header-anchor">#</a> 2. 简单的HTTP协议</h2> <p>HTTP:无状态，一个请求一个响应</p> <p>get：获取资源	post：传输实体	put：传输文件	head：获得报文首部（获得通信状态）	delete：删除</p> <p>options：options * http/1.1 host：www.xxx.com</p> <p>trace: max-forwards</p> <p>connect: ssl tls实现用隧道协议进行tcp通信</p> <h4 id="_1-1特性"><a href="#_1-1特性" class="header-anchor">#</a> 1.1特性</h4> <p>持久连接：一次TCP，多次请求响应</p> <p>管线化：多个请求不等响应回来就发过去，在服务器那边队列处理</p> <p>cookie：响应 &lt;set-cookie: sid=...... 		请求：cookie：sid=......</p> <h2 id="_3-报文"><a href="#_3-报文" class="header-anchor">#</a> 3. 报文</h2> <p>报文首部—空行—报文主体</p> <p>请求：GET	/	HTTP/1.1	Host：www.baidu.com</p> <p>响应：HTTP/1.1	200	OK</p> <p>通用首部：cache-control	connection(keep-alive)	Data	upgrade	via</p> <p>请求首部：accept家族（字符串、编码、语言、媒体类型）	from	host	if家族（匹配更新）	max-forward	range	use-agent</p> <p>响应首部：accept-range：true	age	etag	location（重定向）</p> <p>实体首部：Allow：支持的http方式	content家族（编码、语言、大小。。）	expires（过期时间）	last-modified</p> <p>其他：cookie</p> <h2 id="_4-状态码"><a href="#_4-状态码" class="header-anchor">#</a> 4. 状态码</h2> <p>1	收到（正在处理）</p> <p>2	成功</p> <p>3	要操作（重定向）</p> <p>4	客户端错误</p> <p>5	服务器错误</p> <p>200：ok	204：no content（没有实体部分（没权限、不能反、页面不更新））	206：partial content（range的时候用）</p> <p>301：永久重定向（location）	302：临时重定向	303：（请求对应的资源存在着另一个URI，应使用GET方法定向获取请求的资源）用get	304：not modified	307：临时重定向（明确禁止post变get）</p> <p>400：语法错误	401：要认证	403：forbidden	404：not found</p> <p>500：执行程序的时候发生了错误	503：正忙</p> <h2 id="_5-https"><a href="#_5-https" class="header-anchor">#</a> 5. HTTPS</h2> <h4 id="http存在的问题："><a href="#http存在的问题：" class="header-anchor">#</a> http存在的问题：</h4> <ul><li>通信使用明文可能会被窃听</li> <li>不验证通信方身份，可能遭遇伪装</li> <li>无法证明报文完整性</li></ul> <p>HTTP+加密+认证+完整性保护 = HTTPS</p> <p>SSL：安全嵌套层	TLS</p> <p>原：HTTP — TCP</p> <p>现：先和SSL通信，再由SSL和TCP通信，所谓HTTPS即身披SSL协议这层外壳的HTTP</p> <p><strong>共享密钥加密</strong>：通信前把密钥交给对方</p> <p><strong>公开密钥加密</strong>：发送方用对方的公开密钥进行加密处理，接受方用自己的私有密钥进行解密</p> <h4 id="https采用混合加密机制："><a href="#https采用混合加密机制：" class="header-anchor">#</a> HTTPS采用混合加密机制：</h4> <p>使用公开密钥加密方式安全的交换在稍后的共享密钥中使用的密钥</p> <p>确保交换的密钥是安全的前提下，使用共享密钥加密进行通信</p> <h5 id="通信步骤："><a href="#通信步骤：" class="header-anchor">#</a> 通信步骤：</h5> <ol><li>浏览器植入认证机构公开密钥</li> <li>服务器认证：把公钥交给认证机构</li> <li>认证机构：用私钥签名并还给服务器</li> <li>客户端用公钥验证签名</li> <li>客户端生成随机密码，用公钥加密，交给服务器验证</li> <li>服务器私钥解密，验证</li></ol> <p>SSL一次握手：hello（协商加密组件）/   hello   证书+公钥    done</p> <p>SSL二次握手：随机加密	告诉加密方式	结束（finished） / 	解密	结束</p> <p>HTTP请求，响应</p> <p>断开：客户端close_notify</p> <p>TCP四次挥手</p> <h2 id="_6-http-2-0"><a href="#_6-http-2-0" class="header-anchor">#</a> 6. HTTP 2.0</h2> <p>基于google的SPDY（相当于会话层）</p> <h4 id="http1-1的不足："><a href="#http1-1的不足：" class="header-anchor">#</a> HTTP1.1的不足：</h4> <p>队首阻塞	不分轻重缓急	并行要多次TCP	服务器不能主动推送（一次请求一次响应）	无状态（首部大量冗余信息）</p> <h4 id="二进制分帧："><a href="#二进制分帧：" class="header-anchor">#</a> 二进制分帧：</h4> <p>原先以文本传输</p> <p>现在把数据进行二进制编码，再把数据分成一个个帧，接着把帧放到数据流中。</p> <p>流：一个可用承载双向消息的虚拟信道，每个流都有一个唯一的整数标识符</p> <p>消息：HTTP消息，也就是HTTP报文</p> <p>帧：通信的最小单位，保存着不同类型的数据。</p> <h4 id="特点："><a href="#特点：" class="header-anchor">#</a> 特点：</h4> <p><strong>多路通信</strong>：多路通信只要一次TCP建立</p> <p><strong>请求优先级</strong>：31位优先值，越小越优先</p> <p><strong>服务器推送</strong>：一次请求，推送多个文件</p> <p><strong>首部压缩</strong>：HPACK算法，伪首部，只传不同的部分</p> <h2 id="_7-一些攻击方法"><a href="#_7-一些攻击方法" class="header-anchor">#</a> 7. 一些攻击方法</h2> <h4 id="跨站脚本攻击：xss"><a href="#跨站脚本攻击：xss" class="header-anchor">#</a> 跨站脚本攻击：XSS</h4> <p>骗个人信息，偷cookie，显示伪造文章</p> <p>URL查询字段自动填写，弱将URL查询字段加上script标签，则可运行程序，将URL发给别人，在没注意的情况下就会自动运行</p> <h4 id="sql注入："><a href="#sql注入：" class="header-anchor">#</a> SQL注入：</h4> <p>SELECT * From table WHERE author = ”xx“ and flag = 1；</p> <p>把XX改成”xx&quot;--“,可以把后面的内容注释掉，从而搜索到不该显示的内容</p> <h4 id="跨站点请求伪造："><a href="#跨站点请求伪造：" class="header-anchor">#</a> 跨站点请求伪造：</h4> <p>恶意评论，别人打开网页自动执行。比如图片src里请求一个非图片的东西，会自动运行，可能会把cookie发出去，可能会自动发表一些评论等等。</p> <h1 id="读书笔记：深入浅出vue-js-刘博文"><a href="#读书笔记：深入浅出vue-js-刘博文" class="header-anchor">#</a> 读书笔记：深入浅出Vue.js—刘博文</h1> <p>我个人的学习路线是看视频做项目—看面试题找核心思想—看书懂原理。除了具体操作细节之外，vue的核心无外乎是围绕数据双向绑定。对于这个面试题的解答网上都是甩给你一个object.defineproperty，但是这样看非常不成体系，劫持了之后如何收集依赖、如何触发依赖、怎么生成渲染函数、怎么生成虚拟DOM，怎么更新视图这整个流程还是需要深入理解的。</p> <h2 id="_1-模板编译"><a href="#_1-模板编译" class="header-anchor">#</a> 1. 模板编译</h2> <p>这本书的第一张并不是模板编译，但我还是想把这个放在最前面，因为他解决了我“面对面试题学习”过程中的一个主要困惑——{{}}为什么用了这东西就能在HTML里引用变量了？</p> <h4 id="模板编译在整个渲染过程中的位置："><a href="#模板编译在整个渲染过程中的位置：" class="header-anchor">#</a> 模板编译在整个渲染过程中的位置：</h4> <p>模板——模板编译——渲染函数——vnode——用户界面</p> <p>即模板编译用来生成渲染函数，虚拟DOM则依靠渲染函数生成用户界面。</p> <h4 id="模板编译分三部分内容："><a href="#模板编译分三部分内容：" class="header-anchor">#</a> 模板编译分三部分内容：</h4> <ul><li>将模板解析为AST（抽象语法树）</li> <li>遍历AST标记静态节点</li> <li>使用AST生成渲染函数</li></ul> <p>将这三个部分抽象为三个模块：解析器、优化器、代码生成器。</p> <h5 id="名词解释："><a href="#名词解释：" class="header-anchor">#</a> 名词解释：</h5> <p><strong>AST</strong>：抽象语法树，用对象来表示节点</p> <p><strong>解析器</strong>：HTML解析器、文本解析器、过滤器解析器</p> <p><strong>优化器</strong>：遍历AST，检测出所有静态字数，并给其打标记</p> <h3 id="解析器："><a href="#解析器：" class="header-anchor">#</a> 解析器：</h3> <p>解析器的最终目的是实现这样的功能，解析器是一个函数。</p> <div class="language-js extra-class"><pre class="language-js"><code>			<span class="token function">paseHTML</span><span class="token punctuation">(</span>template<span class="token punctuation">,</span><span class="token punctuation">{</span>
				<span class="token function">start</span><span class="token punctuation">(</span><span class="token parameter">tag<span class="token punctuation">,</span>attrs<span class="token punctuation">,</span>unary</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
					<span class="token comment">//每当解析到标签的开始位置时触发该函数</span>
				<span class="token punctuation">}</span><span class="token punctuation">,</span>
				<span class="token function">end</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
					<span class="token comment">//结束标签触发</span>
				<span class="token punctuation">}</span><span class="token punctuation">,</span>
				<span class="token function">chars</span><span class="token punctuation">(</span><span class="token parameter">text</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
					<span class="token comment">//解析到文本时触发</span>
				<span class="token punctuation">}</span><span class="token punctuation">,</span>
				<span class="token function">comment</span><span class="token punctuation">(</span><span class="token parameter">text</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
					<span class="token comment">//注释时触发	</span>
				<span class="token punctuation">}</span>
			<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre></div><p>比如在钩子函数start中，我们可以运行函数，函数返回一个对象（即AST结构）</p> <p>构建AST层级关系（父子关系）主要是利用栈，我们解析html是从前往后开始，触发start钩子函数的时候将节点推入栈中，触发钩子函数end的时候就从栈中弹出一个节点。比如</p><div><p></p></div>，结构。<p></p> <p>div入栈，栈为空，div没有父节点</p> <p>p入栈，栈尾为div，所以P的父节点是div，并且p会被添加进div的子节点</p> <p>p出栈。</p> <p>div出栈</p> <p>利用正则匹配，对模板进行一小段一小段的截取与解析，直到全部解析完成。</p> <h4 id="原理：html解析器的内部原理是一小段一小段地截取（substring（n））模板字符串，每截取一小段字符串，就会根据截取出来的字符串类型触发不同的钩子函数，直到模板字符串截空停止运行。文本分为两类，有变量和无变量，其中有变量需要用文本解析器进行二次解析。"><a href="#原理：html解析器的内部原理是一小段一小段地截取（substring（n））模板字符串，每截取一小段字符串，就会根据截取出来的字符串类型触发不同的钩子函数，直到模板字符串截空停止运行。文本分为两类，有变量和无变量，其中有变量需要用文本解析器进行二次解析。" class="header-anchor">#</a> 原理：html解析器的内部原理是一小段一小段地截取（substring（n））模板字符串，每截取一小段字符串，就会根据截取出来的字符串类型触发不同的钩子函数，直到模板字符串截空停止运行。文本分为两类，有变量和无变量，其中有变量需要用文本解析器进行二次解析。</h4> <h3 id="优化器："><a href="#优化器：" class="header-anchor">#</a> 优化器：</h3> <p><strong>好处</strong>：每次重新渲染时，不需要为静态子树创建新节点；在虚拟DOM打补丁的过程可以跳过</p> <h4 id="优化器内部实现其实主要分为两个步骤："><a href="#优化器内部实现其实主要分为两个步骤：" class="header-anchor">#</a> 优化器内部实现其实主要分为两个步骤：</h4> <ul><li>在AST中找出所有静态节点并打上标记</li> <li>在AST中找出所有静态根节点并打上标记</li></ul> <p>通过递归的方式从上向下标记静态节点时，如果一个节点被标记为静态节点，但它的子节点却被标记为动态节点，就说明该节点不是静态节点，可以将它改成动态节点。静态节点的特征是它的子节点必须是静态节点。</p> <p>标记完静态节点之后需要标记静态根节点，其标记方式也是使用递归的方式从上向下寻找，在寻找过程中遇到的第一个静态节点就为静态根节点，同时不再向下继续查找。</p> <p>type：1：元素节点，2带变量的动态文本节点，3：不带变量的纯文本节点。</p> <h3 id="代码生成器："><a href="#代码生成器：" class="header-anchor">#</a> 代码生成器：</h3> <p>生成代码字符串是一个递归的过程，从定向下依次处理每一个AST节点。</p> <p>节点有三种类型，对应三种创建方法与别名：</p> <p><strong>元素节点</strong>：createElement _c</p> <p><strong>文本节点</strong>：createTextVNode _v</p> <p><strong>注释节点</strong>：creatEmptyVNode _e</p> <p>一个简单的字符串代码：</p> <p>‘with（this）{return _c(&quot;div&quot;,{attrs:{&quot;id&quot;:&quot;el&quot;}},[ _v(&quot;hello&quot;+ _ s(name))])}’</p> <p>通过递归AST来生成字符串，最先生成根节点，然后在子节点字符串生成后，将其拼接在根节点参数中。</p> <p>静态文本用JSON.stringify('hello')//&quot; 'hello' &quot;</p> <h2 id="_2-变化侦测"><a href="#_2-变化侦测" class="header-anchor">#</a> 2. 变化侦测</h2> <p>变化侦测就是侦测数据的变化。当数据发生变化时，要能侦测到并发出通知。</p> <p>object可以通过defineproperty将属性转换成setter/getter的形式来追踪变化，读取数据时会触发getter，修改数据时会触发setter。</p> <p>我们需要在getter中收集有哪些依赖使用了数据，当setter被触发时，去通知getter中收集的依赖数据发生了变化。</p> <p>收集依赖需要为依赖找一个存储依赖的地方，为此我们创建了Dep类，它用来收集依赖，删除依赖和向依赖发送消息等。</p> <p>所谓依赖，其实就是watch。只有watcher触发的getter才会收集依赖，哪个watcher出发了getter，就把哪个watcher收集到Dep中。当数据发生变化时，会循环依赖列表。把所有的watcher都通知一遍。</p> <p>watcher的原理是先把自己设置到全局唯一的指定位置（例如window。target），然后读取数据。因为读取了数据，所以会触发这个数据的getter。接着，在getter中就会从全局唯一 的那个位置读取当前正在读取数据的watcher，并把这个watcher收集到dep中去。通过这种方式，watcher可以主动去订阅任意一个数据的变化。</p> <p>此外，我们创建了observer类，它的作用是把一个object中的所有数据（包括子数据）都转换成响应式的，也就是他会侦测object的所有数据的变化。</p> <p>由于es6之前没有提供元编程的能力，所以在对象上新增或者删除属性都无法被追踪到。</p> <p>图</p> <p>data通过observer转换成了getter/setter的形式来追踪变化</p> <p>当外界通过watcher读取数据时，会触发getter从而将watcher添加到依赖中。</p> <p>当数据发生了变化时，会触发setter，从而向dep中的依赖（watcher）发送通知。</p> <p>watcher接到通知后，会向外界发送通知，变化通知到外界后可能会触发视图更新，也可能触发用户的某个回调函数。</p> <h3 id="array的变化侦测"><a href="#array的变化侦测" class="header-anchor">#</a> Array的变化侦测:</h3> <p>修改元素是拦截不到的</p> <p>this.arr[0]=2</p> <p>(实测2.6版本在method里这样修改可以侦测到，但在控制台里不行)</p> <p>array的追踪变化的方式和object不一样。因为它是通过方法来改变内容的。所以我们通过拦截器去覆盖数组原型的方式来追踪变化。</p> <p>为了不污染全局array.prototype，我们在observer中只针对那些需要侦测变化的数组使用 _proto _来覆盖原型方法。但该属性在ES6之前不是标准属性。因此，针对不支持的我们直接设置到prototype上来拦截原生方法</p> <p>array收集依赖的方式和object一样，都是在getter中收集。但是由于使用的依赖的位置不同，数组要在拦截器中向依赖发消息，所以依赖不能像object那样保存在definereactive中，而把依赖保存在了observer实例上（proto = arraymethod）。</p> <p>除了侦测数组自生变化外，数组中元素发生变化也要侦测。我们在observer中判断如果当前被侦测的数据是数组，则调用observeArray方法将数组中的每一个元素都转换成响应式，并侦测变化。（数组中的每个子元素都递归调用new observer）</p> <p>除了侦测已有数据外，当用户使用push等方法向数组中新增数据时，新增的数据也要进行变化侦测。我们使用当前操作数组的方法来进行判断，如果是push、unshift、splice方法则从参数中将新增数据提取出来，然后使用observearry对新增数据进行变化侦测。</p> <p>由于在ES5之前，js并没有提供元编程的能力。所以对于数组类型的数据，一些语法无法追踪变化，只能拦截原型上的方法，而无法拦截数组特有语法。</p> <h4 id="一些变化相关的api："><a href="#一些变化相关的api：" class="header-anchor">#</a> 一些变化相关的api：</h4> <p>vm.$watch(obj,fn（new，old，{deep，im}）)</p> <p>观察一个表达式或computed在vuejs上的变化。fn里有new value和oldvalue。还有deep和immediate两个参数，布尔型，deep观察对象内部值的变化。im立即执行。</p> <p>对象的dep里收集了watcher，watcher里同样有哪里dep里收集了它</p> <p>vm.$set(target,key,value)设置属性（obj里的新增，array里的修改(splice)）splice() 方法可删除从 index 处开始的零个或多个元素，并且用参数列表中声明的一个或多个值来替换那些被删除的元素。arrayObject.splice(index,howmany,item1,.....,itemX)</p> <p>vm.$delete(target,key)</p> <h2 id="_3-虚拟dom"><a href="#_3-虚拟dom" class="header-anchor">#</a> 3. 虚拟DOM</h2> <h4 id="虚拟dom简介"><a href="#虚拟dom简介" class="header-anchor">#</a> 虚拟DOM简介</h4> <p>频繁操作DOM会造成很大的开销，虚拟DOM的解决方法时通过状态生成虚拟节点树，然后使用虚拟节点树进行渲染。在渲染之前，会使用新生成的虚拟节点树和上一次生成的虚拟节点数进行对比，只渲染不同的部分。</p> <p>react使用虚拟DOM对比，angular使用脏检查流程。vue2.0选择了一个中等粒度的解决方案，那就是引入了虚拟DOM。组件级别时一个watcher实例。也就是说即便一个组件内有十个节点使用了某个状态，但其实也只有一个watcher在观察这个状态的变化。所以当这个状态发生变化时，只能通知到组件。然后组件内部通过虚拟DOM进行对比与渲染。</p> <p>模板--编译--渲染函数--执行--vnode--patch--视图</p> <h4 id="vnode："><a href="#vnode：" class="header-anchor">#</a> Vnode：</h4> <p>vnode可以理解成节点描述对象，它描述了应该怎样去创建真实的DOM节点。</p> <p>总的来说，VNode是一个类，可以生成不同类型的vnode实例，而不同类型的vnode表示不同类型的真实DOM。</p> <p>vnode会把每次使用的vnode缓存起来，新vnode与老vnode进行对比，只更新需要更新的部分。</p> <h3 id="patch："><a href="#patch：" class="header-anchor">#</a> patch：</h3> <p>虚拟DOM最核心的部分是patch，它可以将vnode渲染成真实dom</p> <p>DOM操作的执行速度远不如JS运行速度快。用patch可以最大限度的减少DOM操作。</p> <p>新增、删除、更新三大操作。</p> <p>创建节点：createElement，以及appendChild</p> <h2 id="_4-生命周期。"><a href="#_4-生命周期。" class="header-anchor">#</a> 4. 生命周期。</h2> <img src="https://cn.vuejs.org/images/lifecycle.png" alt="Vue 实例生命周期" style="zoom:50%;"> <h5 id="在beforecreate和created钩子函数之间的生命周期"><a href="#在beforecreate和created钩子函数之间的生命周期" class="header-anchor">#</a> 在beforeCreate和created钩子函数之间的生命周期**</h5> <p>在这个生命周期之间，进行<strong>初始化事件，进行数据的观测</strong>，可以看到在<strong>created</strong>的时候数据已经和<strong>data属性进行绑定</strong>（放在data中的属性当值发生改变的同时，视图也会改变）。
注意看下：此时还是没有el选项</p> <h5 id="created钩子函数和beforemount间的生命周期：模板编译"><a href="#created钩子函数和beforemount间的生命周期：模板编译" class="header-anchor">#</a> <strong>created钩子函数和beforeMount间的生命周期</strong>：模板编译</h5></div> <footer class="page-edit"><!----> <!----></footer> <!----> </main></div><div class="global-ui"></div></div>
    <script src="/ytblog/assets/js/app.5ba5dcf6.js" defer></script><script src="/ytblog/assets/js/2.f25dafc3.js" defer></script><script src="/ytblog/assets/js/6.60c7b6d3.js" defer></script>
  </body>
</html>
